package com.dh.example.io.manager;

import cn.hutool.core.map.MapUtil;
import com.corundumstudio.socketio.SocketIOClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;


/**
 * 套接字客户端管理器
 *
 * @author yolo
 * @date 2024/03/06 17:05:30
 */
@Component
@Slf4j
public class SocketClientManager implements SocketClientInterface {

    /**
     * 客户端映射 Map<clientType+userId,<sessionId,client>>
     */
    private final ConcurrentHashMap<String, ConcurrentHashMap<String, SocketIOClient>> CLIENTS_MAP = new ConcurrentHashMap<>();

    @Override
    public void saveSocketClient(SocketIOClient client) {
        String keyClient = getKeyClient(client);
        if (CLIENTS_MAP.containsKey(keyClient)) {
            log.info("存在对应的key：{}", keyClient);
            ConcurrentHashMap<String, SocketIOClient> clientsMap = CLIENTS_MAP.get(keyClient);
            clientsMap.put(client.getSessionId().toString(), client);
            log.info("目前存在的客户端数量：{}", clientsMap.size());
        } else {
            ConcurrentHashMap<String, SocketIOClient> clients = new ConcurrentHashMap<>();
            clients.put(client.getSessionId().toString(), client);
            CLIENTS_MAP.put(keyClient, clients);
        }
    }

    @Override
    public void delSocketClient(SocketIOClient client) {
        String keyClient = getKeyClient(client);
        if (CLIENTS_MAP.containsKey(keyClient)) {
            ConcurrentHashMap<String, SocketIOClient> clientsMap = CLIENTS_MAP.get(keyClient);
            clientsMap.remove(client.getSessionId().toString());
            if (MapUtil.isEmpty(clientsMap)) {
                CLIENTS_MAP.remove(keyClient);
            }
            log.info("目前存在的客户端数量：{}", clientsMap.size());
        }
    }

    @Override
    public void sendAll(String eventType, String bodyStr) {
        for (ConcurrentHashMap<String, SocketIOClient> value : CLIENTS_MAP.values()) {
            for (SocketIOClient socketIoClient : value.values()) {
                send(socketIoClient, eventType, bodyStr);
            }
        }
    }

    @Override
    public void send(String token, String clientType, String eventType, String bodyStr) {
        // 获取对应的会话连接
        ConcurrentHashMap<String, SocketIOClient> clientMap = CLIENTS_MAP.get(getKey(clientType, token));
        if (MapUtil.isEmpty(clientMap)) {
            log.warn("客户端连接不存在:{}:{},bodyStr:{}", clientType, token, bodyStr);
            return;
        }
        clientMap.forEach((sessionId, client) -> send(client, eventType, bodyStr));
    }


    /**
     * 发送
     *
     * @param socketIoClient 套接字io客户端
     * @param eventType      事件名称
     * @param bodyStr        身体力量
     */
    private void send(SocketIOClient socketIoClient, String eventType, String bodyStr) {
        try {
            socketIoClient.sendEvent(eventType, bodyStr);
        } catch (Exception e) {
            // 发送异常进行删除对应会话连接
            log.warn("{}发送消息异常,关闭连接:", socketIoClient.getSessionId().toString(), e);
            delSocketClient(socketIoClient);
        }
    }


    private String getKeyClient(SocketIOClient client) {
        String token = getParamByClient(client, "token");
        String clientType = getParamByClient(client, "clientType");
        return getKey(clientType, token);
    }


    private String getKey(String clientType, String token) {
        return clientType + "_" + token;
    }

    /**
     * 通过客户端获取用户id
     *
     * @param client 客户
     * @return {@code Long}
     */
    private String getParamByClient(SocketIOClient client, String paramName) {
        return client.getHandshakeData().getSingleUrlParam(paramName);
    }
}
